﻿// <author>Netmon Cipher Dev Team</author>
// <date>2009-07-16</date>
// <version>1.0</version>
// <summary>This contains the entry point Main function.</summary>

namespace SSLDecryptionExpert
{
    using System;

    /// <summary>
    /// SSL Decryption Class
    /// </summary>
    public partial class SSLDecryption
    {
        #region Compute Keys For Application Data Decryption

        /// <summary>
        /// Compute Keys
        /// </summary>
        /// <param name="isClientKeyExchange">
        /// Checks if message is Client Key Exchange</param>
        /// <param name="isKeyBlockComputed">TRUE if KeyBlock is computed.</param>
        /// <param name="keyExchangeData">Key Exchange Data</param>
        /// <param name="cipherSuiteInfo">Cipher Suite Information</param>
        /// <returns>Returns TRUE if success</returns>
        private bool ComputeKeys(
                        bool isClientKeyExchange,
                        ref bool isKeyBlockComputed,
                        byte[] keyExchangeData,
                        Variables.CipherSuiteInfo cipherSuiteInfo)
        {
            bool result = true;

            if (isClientKeyExchange)
            {
                Variables.Log.LogMessage("Computing Pre Master Secret...");
                result = AppDataDecryption.ComputePreMasterKey(
                                            this.certificateFilePath,
                                            this.certificatePassword,
                                            keyExchangeData,
                                            cipherSuiteInfo);
                if (!result)
                {
                    return result;
                }

                Variables.Log.LogMessage("Computing Master Secret...");
                result = AppDataDecryption.ComputeMasterSecretKey(cipherSuiteInfo);
                if (!result)
                {
                    return result;
                }
            }

            Variables.Log.LogMessage("Computing Key Block...");
            result = AppDataDecryption.ComputeKeyBlock(cipherSuiteInfo);
            if (!result)
            {
                if (isClientKeyExchange)
                {
                    Variables.Log.DisplayException("Error in Computing KeyBlock");
                }
                else
                {
                    Variables.Log.DisplayException("Client Key Exchange Data is missing.");
                }

                return result;
            }

            isKeyBlockComputed = true;

            return result;
        }

        #endregion

        #region Fill Selected Cipher Suite Information

        /// <summary>
        /// Fills the Selected Cipher Suite Information
        /// </summary>
        private void FillSelectedCipherSuiteInfo()
        {
            switch (Variables.selectedCipherSuite)
            {
                case CipherSuite.TLS_RSA_WITH_NULL_MD5:

                    this.FillCipherInfo(
                                KeyExchangeAlgorithm.RSA,
                                DataEncryptionMethod.NULL,
                                CipherMode.None,
                                MAC.MD5,
                                CipherBlockSize.NULL);
                    break;

                case CipherSuite.TLS_RSA_WITH_NULL_SHA:

                    this.FillCipherInfo(
                                KeyExchangeAlgorithm.RSA,
                                DataEncryptionMethod.NULL,
                                CipherMode.None,
                                MAC.SHA1,
                                CipherBlockSize.NULL);
                    break;

                case CipherSuite.TLS_RSA_WITH_RC4_128_MD5:

                    this.FillCipherInfo(
                                KeyExchangeAlgorithm.RSA,
                                DataEncryptionMethod.RC4_128,
                                CipherMode.None,
                                MAC.MD5,
                                CipherBlockSize.NULL);
                    break;

                case CipherSuite.TLS_RSA_WITH_RC4_128_SHA:

                    this.FillCipherInfo(
                                KeyExchangeAlgorithm.RSA,
                                DataEncryptionMethod.RC4_128,
                                CipherMode.None,
                                MAC.SHA1,
                                CipherBlockSize.NULL);
                    break;   

                case CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA:

                    this.FillCipherInfo(
                                KeyExchangeAlgorithm.RSA,
                                DataEncryptionMethod.DES3_EDE,
                                CipherMode.CBC,
                                MAC.SHA1,
                                CipherBlockSize.DES);
                    break;

                case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA:

                    this.FillCipherInfo(
                                KeyExchangeAlgorithm.RSA,
                                DataEncryptionMethod.AES128,
                                CipherMode.CBC,
                                MAC.SHA1,
                                CipherBlockSize.AES);
                    break;

                case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA:

                    this.FillCipherInfo(
                                KeyExchangeAlgorithm.RSA,
                                DataEncryptionMethod.AES256,
                                CipherMode.CBC,
                                MAC.SHA1,
                                CipherBlockSize.AES);
                    break;

                case CipherSuite.SSL2_RC4_128_MD5:

                    this.FillCipherInfo(
                                KeyExchangeAlgorithm.RSA,
                                DataEncryptionMethod.RC4_128,
                                CipherMode.None,
                                MAC.MD5,
                                CipherBlockSize.NULL);
                    break;

                case CipherSuite.SSL2_DES_192_EDE3_CBC_WITH_MD5:

                    this.FillCipherInfo(
                                KeyExchangeAlgorithm.RSA,
                                DataEncryptionMethod.DES3_EDE,
                                CipherMode.CBC,
                                MAC.MD5,
                                CipherBlockSize.NULL);
                    break;
            }
        }

        #endregion

        #region Fill Cipher Information

        /// <summary>
        /// Fills the Cipher Suite Information
        /// </summary>
        /// <param name="keyAlgo">Key Exchange Algorithm</param>
        /// <param name="dataEncryption">Data Encryption Method</param>
        /// <param name="mode">Cipher Suite Mode</param>
        /// <param name="mac">Algorithm for MAC</param>
        /// <param name="blockSize">Bit-String Size of Cipher</param>
        private void FillCipherInfo(
                            KeyExchangeAlgorithm keyAlgo,
                            DataEncryptionMethod dataEncryption,
                            CipherMode mode,
                            MAC mac,
                            CipherBlockSize blockSize)
        {
            cipherSuiteInfo.KeyExchangeAlg = keyAlgo;
            cipherSuiteInfo.DataEncryption = dataEncryption;
            cipherSuiteInfo.MacType = mac;
            cipherSuiteInfo.CipherMode = mode;
            cipherSuiteInfo.BlockSize = blockSize;
        }

        #endregion

        #region CalculateKeyBlockLength

        /// <summary>
        /// Calculates Key Block Length
        /// </summary>
        /// <returns>
        /// Returns TRUE on Success
        /// </returns>
        private bool CalculateKeyBlockLength()
        {
            bool status = true;

            switch (Variables.selectedCipherSuite)
            {
                case CipherSuite.TLS_RSA_WITH_NULL_MD5:
                    this.AssignKeyLength(16, 0, 0);
                    break;

                case CipherSuite.TLS_RSA_WITH_NULL_SHA:
                    this.AssignKeyLength(20, 0, 0);
                    break;

                case CipherSuite.TLS_RSA_WITH_RC4_128_MD5:
                    this.AssignKeyLength(16, 16, 0);
                    break;

                case CipherSuite.TLS_RSA_WITH_RC4_128_SHA:
                    this.AssignKeyLength(20, 16, 0);
                    break;

                case CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA:
                    this.AssignKeyLength(20, 24, 8);
                    break;                

                case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA:
                    this.AssignKeyLength(20, 16, 16);                    
                    break;

                case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA:
                    this.AssignKeyLength(20, 32, 16);
                    break;
            
                case 0:

                    //// This indicates there was no
                    //// handshake prior to this message.
                    status = false;
                    break;
            }

            if (status)
            {
                Variables.keyBlock = new byte[Variables.clientMacWriteKey.Length +
                                                Variables.serverMacWriteKey.Length +
                                                Variables.clientWriteKey.Length +
                                                Variables.serverWriteKey.Length +
                                                Variables.clientCipherDataIV.Length +
                                                Variables.serverCipherDataIV.Length];
            }
            else
            {
                  Variables.Log.DisplayException(
                                "Unable to find Cipher Suite." +
                                " Looking for " + filter.CipherSuiteFilter);
/*                Variables.log.DisplayException(
                                "Client/Server Hello Messages are missing," +
                                " Improper Handshake Sequence");*/
            }

            return status;
        }

        #endregion

        #region AssignKeyLength

        /// <summary>
        /// Assigns the Key Length
        /// </summary>
        /// <param name="macWriteKeyLength">Mac Write Key Length</param>
        /// <param name="writeKeyLength">Write Key Length</param>
        /// <param name="lengthIV">Length of IV</param>
        private void AssignKeyLength(
                            int macWriteKeyLength,
                            int writeKeyLength,
                            int lengthIV)
        {
            Variables.clientMacWriteKey = new byte[macWriteKeyLength];
            Variables.serverMacWriteKey = new byte[macWriteKeyLength];
            Variables.clientWriteKey = new byte[writeKeyLength];
            Variables.serverWriteKey = new byte[writeKeyLength];
            Variables.clientCipherDataIV = new byte[lengthIV];
            Variables.serverCipherDataIV = new byte[lengthIV];
        }

        #endregion 
    }
}